package com.wanqing.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wanqing.context.BaseContext;
import com.wanqing.dto.UserVoucherPageQueryDTO;
import com.wanqing.dto.VoucherDTO;
import com.wanqing.dto.VoucherPageQueryDTO;
import com.wanqing.dto.VoucherReceiveDTO;
import com.wanqing.entity.UserVoucher;
import com.wanqing.entity.Voucher;
import com.wanqing.entity.VoucherRule;
import com.wanqing.exception.VoucherException;
import com.wanqing.mapper.VoucherMapper;
import com.wanqing.result.PageResult;
import com.wanqing.service.VoucherService;
import com.wanqing.vo.UserVoucherVO;
import com.wanqing.vo.VoucherVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 优惠券服务实现类
 * 实现优惠券管理的核心业务逻辑
 */
@Service
@Slf4j
public class VoucherServiceImpl implements VoucherService {

    @Autowired
    private VoucherMapper voucherMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createVoucher(VoucherDTO dto) {
        validateVoucherRule(dto);
        // 4. 保存主表
        Voucher voucher = new Voucher();
        BeanUtils.copyProperties(dto, voucher);
        voucher.setStatus((byte) 1); // 默认为上架
        voucherMapper.insertVoucher(voucher);
        log.info("保存优惠券成功，优惠券ID：{}", voucher.getId());
        // 5. 保存规则表
        VoucherRule voucherRule = dto.getVoucherRule();
        voucherRule.setVoucherId(voucher.getId());
        voucherMapper.insertRule(voucherRule);
    }

    private void validateVoucherRule(VoucherDTO dto) {
        // 1. 基础校验
        if (dto.getValidStartTime().isAfter(dto.getValidEndTime())) {
            throw new VoucherException("有效期开始时间不能晚于结束时间");
        }

        // 2. 秒杀券特殊校验
        if (dto.getType() == 1) {
            if (dto.getSeckillStartTime() == null || dto.getSeckillEndTime() == null) {
                throw new VoucherException("秒杀券必须填写秒杀时间");
            }
            if (dto.getSeckillStartTime().isAfter(dto.getSeckillEndTime())) {
                throw new VoucherException("秒杀开始时间不能晚于结束时间");
            }
            if (dto.getSeckillEndTime().isAfter(dto.getValidEndTime())) {
                throw new VoucherException("秒杀结束时间不能晚于通用有效期结束时间");
            }
        }
        VoucherRule voucherRule = dto.getVoucherRule();
        // 3. 优惠规则校验
        if (voucherRule.getDiscountType() == 0 && (voucherRule.getMinAmount() == null || voucherRule.getMinAmount().compareTo(BigDecimal.ZERO) <= 0)) {
            throw new VoucherException("满减券必须设置有效门槛金额");
        }
        if (voucherRule.getDiscountValue().compareTo(BigDecimal.ZERO) <= 0) {
            throw new VoucherException("优惠值必须大于0");
        }
    }

    @Override
    public VoucherVO getVoucherDetail(Long id) {
        VoucherVO voucherVO = voucherMapper.selectVoucherVOById(id);
        if (voucherVO == null) {
            throw new VoucherException("优惠券不存在");
        }
        // 补充规则描述
        this.fillVoucherVODesc(voucherVO);
        return voucherVO;
    }

    // 填充优惠券VO的规则描述
    private void fillVoucherVODesc(VoucherVO vo) {

        // 1. 有效期范围
        vo.setValidTimeRange(vo.getValidStartTime(), vo.getValidEndTime());
        // 2. 秒杀时间范围
        vo.setSeckillTimeRange(vo.getSeckillStartTime(), vo.getSeckillEndTime());
        // 3. 优惠规则描述
        VoucherRule voucherRule = vo.getVoucherRule();
        if (voucherRule.getDiscountType() == 0) {
            vo.setDiscountDesc("满" + voucherRule.getMinAmount() + "减" + voucherRule.getDiscountValue());
        } else if (voucherRule.getDiscountType() == 1) {
            vo.setDiscountDesc(voucherRule.getDiscountValue() + "折");
        } else {
            vo.setDiscountDesc("立减" + voucherRule.getDiscountValue());
        }
        // 4. 限用条件描述
        StringBuilder limitDesc = new StringBuilder();
        if (voucherRule.getLimitCategory() != null && !voucherRule.getLimitCategory().isEmpty()) {
            limitDesc.append("限品类：").append(voucherRule.getLimitCategory()).append("；");
        }
        if (voucherRule.getLimitUserLevel() != null) {
            limitDesc.append("限").append(voucherRule.getLimitUserLevel() == 1 ? "普通用户" : "会员").append("使用；");
        }
        if (voucherRule.getPerUserLimit() != null && voucherRule.getPerUserLimit() > 0) {
            limitDesc.append("每人限领").append(voucherRule.getPerUserLimit()).append("张");
        }
        vo.setLimitDesc(limitDesc.toString());
    }

    /**
     * 获取优惠券列表
     *
     * @param voucherPageQueryDTO
     * @return
     */
    @Override
    public PageResult getVoucherList(VoucherPageQueryDTO voucherPageQueryDTO) {
        // 参数校验
        if (voucherPageQueryDTO.getPage() == null || voucherPageQueryDTO.getPageSize() == null) {
            throw new VoucherException("分页参数不能为空");
        }
        // 校验有无过期优惠券
        checkExpiredVoucher();
        // 开始分页
        PageHelper.startPage(voucherPageQueryDTO.getPage(), voucherPageQueryDTO.getPageSize());
        Page<VoucherVO> page = voucherMapper.selectVoucherVOList(voucherPageQueryDTO);
        page.getResult().forEach(this::fillVoucherVODesc);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 更新优惠券信息
     */
    @Override
    @Transactional
    public void updateVoucher(VoucherDTO voucherDTO) {
        validateVoucherRule(voucherDTO);
        // 3. 更新主表
        Voucher voucher = new Voucher();
        BeanUtils.copyProperties(voucherDTO, voucher);
        voucherMapper.updateVoucherById(voucher);

        // 4. 更新规则表
        VoucherRule voucherRule = voucherDTO.getVoucherRule();
        voucherMapper.updateRuleById(voucherRule);
    }

    @Override
    public void updateVoucherStatus(Long id, Byte status) {
        //如果要上架先检查优惠券是否过期，如果已过期则不允许上架
        if (status == 1) {
            Voucher voucher = voucherMapper.getById(id);
            boolean isExpired = voucher.getSeckillEndTime().isBefore(LocalDateTime.now());
            if (isExpired) {
                throw new VoucherException("优惠券已过期，不能上架");
            }
        }
        if (status != 2 && status != 1) {
            throw new VoucherException("优惠券状态错误");
        }
        Voucher voucher = new Voucher();
        voucher.setId(id);
        voucher.setStatus(status);
        voucherMapper.updateVoucherById(voucher);
    }

    @Override
    @Transactional
    public void deleteBatch(List<Long> ids) {
        //检查优惠券是否上架，如果已上架，则不允许删除
        for (Long id : ids) {
            Voucher voucher = voucherMapper.getById(id);
            if (voucher.getStatus() == 1) {
                throw new VoucherException("优惠券已上架，不能删除");
            }
        }
        voucherMapper.deleteBatch(ids);
        voucherMapper.deleteRuleBatch(ids);
    }


    /**
     * 用户领取优惠券
     *
     * @param dto
     */
    @Override
    @Transactional
    public void receiveVoucher(VoucherReceiveDTO dto) {
        Long userId = BaseContext.getCurrentId();
        Long voucherId = dto.getVoucherId();
        LocalDateTime now = LocalDateTime.now();
        // 1. 查询优惠券信息
        Voucher voucher = voucherMapper.selectById(voucherId);
        if (voucher == null || voucher.getStatus() != 1) {
            throw new VoucherException("优惠券不存在或未上架");
        }

        // 2. 秒杀券校验秒杀时间 校验库存 校验用户限领数量
        if (voucher.getType() == 1) {
            if (now.isBefore(voucher.getSeckillStartTime()) || now.isAfter(voucher.getSeckillEndTime())) {
                throw new VoucherException("不在秒杀时间范围内");
            }
            if (voucher.getStock() <= 0) {
                throw new VoucherException("优惠券已抢完");
            }
            // 校验用户限领数量
            VoucherRule rule = voucherMapper.getRuleByVoucherId(voucherId);
            int receivedCount = voucherMapper.getReceivedCount(userId, voucherId);
            if (receivedCount >= rule.getPerUserLimit()) {
                throw new VoucherException("已超过用户限领数量");
            }
            // 有秒杀资格 开始扣减库存
            int rows = voucherMapper.reduceStock(voucherId);
            if (rows == 0) {
                throw new VoucherException("优惠券已抢完");
            }
            // 6. 保存领取记录
            LocalDateTime validStartTime = voucher.getValidStartTime();
            UserVoucher userVoucher = UserVoucher.builder()
                    .receiveTime(now)
                    .validStartTime(validStartTime.isAfter(now) ? validStartTime : now)
                    .validEndTime(voucher.getValidEndTime())
                    .status((byte) 0)
                    .source(dto.getSource())
                    .createTime(now)
                    .updateTime(now)
                    .build();
            voucherMapper.insertUserVoucher(userVoucher);
        } else {
            if (voucher.getStock() <= 0) {
                throw new VoucherException("优惠券已抢完");
            }
            // 校验用户限领数量
            VoucherRule rule = voucherMapper.getRuleByVoucherId(voucherId);
            int receivedCount = voucherMapper.getReceivedCount(userId, voucherId);
            if (receivedCount >= rule.getPerUserLimit()) {
                throw new VoucherException("已超过用户限领数量");
            }

            int rows = voucherMapper.reduceStock(voucherId);
            if (rows == 0) {
                throw new VoucherException("优惠券已抢完");
            }

            // 6. 保存领取记录
            LocalDateTime validStartTime = voucher.getValidStartTime();
            UserVoucher userVoucher = UserVoucher.builder()
                    .receiveTime(now)
                    .validStartTime(validStartTime.isAfter(now) ? validStartTime : now)
                    .validEndTime(voucher.getValidEndTime())
                    .status((byte) 0)
                    .source(dto.getSource())
                    .createTime(now)
                    .updateTime(now)
                    .build();
            voucherMapper.insertUserVoucher(userVoucher);
        }
    }

    /**
     * 用户端展示优惠券
     *
     * @return
     */
    @Override
    public List<VoucherVO> getVoucherListUser() {
        // 检查管理端过期优惠券并直接下架
        checkExpiredVoucher();
        // 查询所有上架的优惠券
        VoucherPageQueryDTO voucherPageQueryDTO = new VoucherPageQueryDTO();
        voucherPageQueryDTO.setStatus((byte) 1);
        Page<VoucherVO> page = voucherMapper.selectVoucherVOList(voucherPageQueryDTO);
        List<VoucherVO> voucherVOList = page.getResult();
        voucherVOList.forEach(this::fillVoucherVODesc);
        return voucherVOList;
    }

    /**
     * 获取用户优惠券规则
     *
     * @param id
     * @return
     */
    @Override
    public VoucherRule getUserVoucherRuleById(Long id) {
        Long voucherId = voucherMapper.getVoucherId(id);
        return voucherMapper.getVoucherRuleById(voucherId);
    }

    /**
     * 查看当前用户优惠券列表
     *
     * @param userVoucherPageQueryDTO
     * @return
     */
    @Override
    public PageResult listUserVouchers(UserVoucherPageQueryDTO userVoucherPageQueryDTO) {
        // 检查是否存在过期优惠券
        checkExpiredUserVoucher();
        PageHelper.startPage(userVoucherPageQueryDTO.getPage(), userVoucherPageQueryDTO.getPageSize());
        userVoucherPageQueryDTO.setUserId(BaseContext.getCurrentId());
        Page<UserVoucherVO> page = voucherMapper.selectUserVoucherVOList(userVoucherPageQueryDTO);
        List<UserVoucherVO> list = page.getResult();
        // 补充剩余天数描述
        list.forEach(vo -> {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime validStartTime = vo.getValidStartTime();
            LocalDateTime beginTime = vo.getValidStartTime().isAfter(now) ? validStartTime : now;
            long remainDays = ChronoUnit.DAYS.between(beginTime, vo.getValidEndTime());
            vo.setRemainDaysDesc(remainDays > 0 ? "还剩" + remainDays + "天" : "今日过期");
        });

        return new PageResult(page.getTotal(), list);
    }

    /**
     * 使用优惠券
     *
     * @param id
     * @param orderId
     */
    @Override
    public void useVoucher(Long id, Long orderId) {
        checkExpiredUserVoucher();
        UserVoucher userVoucher = UserVoucher.builder()
                .id(id)
                .status((byte) 1)
                .orderId(orderId)
                .useTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        int rows = voucherMapper.updateUserVoucherStatus(userVoucher);
        if (rows == 0) {
            throw new VoucherException("优惠券已使用或已过期");
        }
    }

    /**
     * 检查用户过期的优惠券并更新状态
     */
    public void checkExpiredUserVoucher() {
        try {
            // 检查未使用的券有没有过期的券
            List<UserVoucher> expiredUserVouchers = voucherMapper.checkExpiredUserVoucher();

            if (CollUtil.isEmpty(expiredUserVouchers)) {
                log.info("没有找到过期的用户券");
                return;
            }

            log.info("开始处理过期用户券，数量: {}", expiredUserVouchers.size());

            // 使用批量更新
            List<Long> expiredUserVoucherIds = expiredUserVouchers.stream()
                    .map(UserVoucher::getId)
                    .collect(Collectors.toList());

            voucherMapper.batchUpdateExpiredUserVoucherStatus(expiredUserVoucherIds, (byte) 2);
        } catch (Exception e) {
            log.error("处理过期用户券失败", e);
        }
    }


    /**
     * 检查管理端过期优惠券并直接下架
     */
    public void checkExpiredVoucher() {
        try {
            // 检查未使用的券有没有过期的券
            List<Voucher> voucherList = voucherMapper.checkExpiredVoucher();
            // 下架已过期的券
            if (CollUtil.isNotEmpty(voucherList)) {
                log.info("开始下架过期券，数量: {}", voucherList.size());
                List<Long> voucherIds = voucherList.stream()
                        .map(Voucher::getId)
                        .collect(Collectors.toList());
                voucherMapper.batchUpdateExpiredVoucher(voucherIds, (byte) 2);
            }

        } catch (Exception e) {
            // 记录日志
            log.error("下架过期券失败", e);
        }

    }
}
